#pragma once

#include "event/znx_conn.h"
#include "event/znx_openssl.h"
#include "event/znx_event_loop.h"
#include "http/znx_http_log.h"


typedef struct znx_http_conn_s      znx_http_conn_t;
typedef void (*znx_http_conn_handler)(znx_http_conn_t *hc);


struct znx_http_conn_s {
    znx_pool_t                      *pool;

    znx_conn_t                      *c;
    znx_http_log_t                  hlog;

    // context
    void                            *data;
    znx_http_conn_handler           read_handler;
    znx_http_conn_handler           write_handler;
    znx_http_conn_handler           close_handler;
    znx_http_conn_handler           keepalive_handler;

    znx_queue_t                     queue;  // for keepalive

    znx_buf_t                       *pre_buf;

    unsigned                        read_active:1;
    unsigned                        write_active:1;
};


static inline znx_bool_t
znx_http_conn_start_io(znx_http_conn_t *hc)
{
    if (hc->c->type == ZNX_TCP_CONN ||
        hc->c->type == ZNX_UDP_CONN)
    {
        return znx_event_loop_start_io(hc->c);
    }

    return ZNX_FALSE;
}


static inline znx_bool_t
znx_http_conn_stop_io(znx_http_conn_t *hc)
{
    if (hc->c->type == ZNX_TCP_CONN ||
        hc->c->type == ZNX_UDP_CONN)
    {
        return znx_event_loop_stop_io(hc->c);
    }

    return ZNX_FALSE;
}


static inline znx_bool_t
znx_http_conn_enable_read(znx_http_conn_t *hc)
{
    hc->read_active = 1;

    if (hc->c->type == ZNX_TCP_CONN ||
        hc->c->type == ZNX_UDP_CONN)
    {
        return znx_event_loop_enable_read(hc->c);
    }

    return ZNX_FALSE;
}


static inline znx_bool_t
znx_http_conn_disable_read(znx_http_conn_t *hc)
{
    hc->read_active = 0;
    return ZNX_TRUE;
}


static inline znx_bool_t
znx_http_conn_read_ready(znx_http_conn_t *hc)
{
    if (hc->c->read.ready) {
        return ZNX_TRUE;
    }

    return ZNX_FALSE;
}


static inline znx_bool_t
znx_http_conn_enable_write(znx_http_conn_t *hc)
{
    hc->write_active = 1;

    if (hc->c->type == ZNX_TCP_CONN ||
        hc->c->type == ZNX_UDP_CONN)
    {
        return znx_event_loop_enable_write(hc->c);
    }

    return ZNX_FALSE;
}


static inline znx_bool_t
znx_http_conn_disable_write(znx_http_conn_t *hc)
{
    hc->write_active = 0;
    return ZNX_TRUE;
}


static inline znx_bool_t
znx_http_conn_write_ready(znx_http_conn_t *hc)
{
    if (hc->c->write.ready) {
        return ZNX_TRUE;
    }

    return ZNX_FALSE;
}


void znx_http_conn_close(znx_http_conn_t *hc,
    znx_http_conn_handler close_handler);


static inline znx_result_t
znx_http_conn_read(znx_http_conn_t *hc, void *buf, size_t count)
{
    return hc->c->operator->read(hc->c, buf, count);
}


static inline znx_result_t
znx_http_conn_readv(znx_http_conn_t *hc, znx_iovec_t *vector, int iovcnt)
{
    return hc->c->operator->readv(hc->c, vector, iovcnt);
}


static inline znx_result_t
znx_http_conn_write(znx_http_conn_t *hc, void *buf, size_t count)
{
    return hc->c->operator->write(hc->c, buf, count);
}

static inline znx_result_t
znx_http_conn_writev(znx_http_conn_t *hc, znx_iovec_t *vector, int iovcnt)
{
    return hc->c->operator->writev(hc->c, vector, iovcnt);
}


void znx_http_conn_event_handler(znx_event_t *event);


static inline znx_http_conn_t *
znx_http_conn_create(znx_conn_t *c)
{
    znx_http_conn_t *hc;
    znx_pool_t  *pool = znx_pool_create();
    hc = znx_pool_calloc(pool, sizeof(znx_http_conn_t));
    hc->pool = pool;
    hc->c = c;
    c->data = hc;
    hc->hlog.log = &def_log;
    hc->c->read.handler = znx_http_conn_event_handler;
    hc->c->write.handler = znx_http_conn_event_handler;
    return hc;
}


// only use in http server conn keepalive.
static inline void
znx_http_conn_deep_copy(znx_http_conn_t *dst, const znx_http_conn_t *src)
{
    dst->keepalive_handler = src->keepalive_handler;
}


static inline void
znx_http_conn_destroy(znx_http_conn_t *hc)
{
    znx_pool_destroy(hc->pool);
}
